package com.xyzwps.server.paimon.it

import com.xyzwps.server.paimon.app.dto.Me
import com.xyzwps.server.paimon.common.Utils
import com.xyzwps.server.paimon.value.UserId
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.http.MediaType
import org.springframework.http.ProblemDetail
import org.junit.jupiter.api.Assertions.*

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MvcRegisterAndLoginTests(@LocalServerPort port: Int) : MvcTestBase(port) {

    data class RLHolder(
        var registerDkey: String? = null,
        var loginDkey: String? = null,
        var token: String? = null,
        var id: UserId? = null,
        var nickname: String? = null
    )

    @Test
    fun registerAndLoginTest() {
        webClient.get().uri("/apis/me")
            .exchange()
            .expectStatus().is4xxClientError()
            .expectBody(ProblemDetail::class.java)
            .value { p ->
                assertEquals("/errors/100", p.type.toString())
                assertEquals("UNAUTHORIZED", p.title)
                assertEquals(401, p.status)
            }

        val phone = UiTestHelper.genPhone()
        val holder = RLHolder()
        webClient.post().uri("/apis/register/send-vcode")
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(mapOf("phone" to phone))
            .exchange()
            .expectStatus().isOk
            .expectBody()
            .jsonPath("$.data").value<String> { dkey -> holder.registerDkey = dkey }
        assertNotNull(holder.registerDkey)

        webClient.post().uri("/apis/register")
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(mapOf("phone" to phone, "vcode" to "666666", "dkey" to holder.registerDkey))
            .exchange()
            .expectStatus().isOk
            .expectBody()
            .jsonPath("$.data").isEmpty

        webClient.post().uri("/apis/login/send-vcode")
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(mapOf("phone" to phone))
            .exchange()
            .expectStatus().isOk
            .expectBody()
            .jsonPath("$.data").value<String> { dkey -> holder.loginDkey = dkey }
        assertNotNull(holder.loginDkey)

        webClient.post().uri("/apis/login")
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(mapOf("phone" to phone, "vcode" to "666666", "dkey" to holder.loginDkey))
            .exchange()
            .expectStatus().isOk
            .expectBody()
            .jsonPath("$.data")
            .value(Me::class.java) { me ->
                assertNotNull(me.id)
                assertEquals(Utils.maskPhone(phone), me.nickname)
                assertNotNull(me.createdAt)
                assertNotNull(me.token)

                holder.id = me.id
                holder.nickname = me.nickname
                holder.token = me.token
            }

        webClient.get().uri("/apis/me")
            .header("Authorization", "Bearer ${holder.token}")
            .exchange()
            .expectStatus().isOk
            .expectBody()
            .jsonPath("$.data")
            .value(Me::class.java) { me ->
                assertEquals(holder.id, me.id)
                assertEquals(holder.nickname, me.nickname)
                assertNotNull(me.createdAt)
                assertNull(me.token)
            }
    }
}
